package com.lingjtx.im.core.handle;

import com.lingjtx.common.core.token.AuthToken;
import com.lingjtx.common.core.token.UserDetail;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.redis.config.ServerNodeConfig;
import com.lingjtx.common.redis.service.IRedisService;
import com.lingjtx.im.core.common.SessionManager;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@ChannelHandler.Sharable
@Component
public class AuthHandshakeHandler extends ChannelInboundHandlerAdapter {

    private boolean passed = false;

    private final IRedisService redisService;

    private final ServerNodeConfig serverNodeConfig;

    public AuthHandshakeHandler(IRedisService redisService, ServerNodeConfig serverNodeConfig) {
        this.redisService = redisService;
        this.serverNodeConfig = serverNodeConfig;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest request) {
            String token = getTokenFromRequest(request);

            // 鉴权失败
            if (StringUtil.isEmpty(token) || AuthToken.isExpTime(token)) {
                sendHttpResponse(ctx);
                ReferenceCountUtil.release(msg); // 释放引用，防止内存泄漏
                ctx.close();
                log.warn("WebSocket 鉴权失败，token 无效：{}", token);
                return;
            }

            // 鉴权成功，绑定用户
            UserDetail userDetail = AuthToken.getUser(token);
            SessionManager.registerSession(userDetail, ctx.channel(), serverNodeConfig.getNodeId(), redisService);

            // 清理 URI 中的 token 参数，避免 WebSocket 协议不匹配路径
            QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
            String cleanUri = decoder.path(); // 只保留路径，不带参数
            request.setUri(cleanUri);

            passed = true;
            log.info("WebSocket 鉴权成功，用户ID: {}", userDetail.getUserId());
        }

        // 放行所有消息，包括握手最后的 EmptyLastHttpContent
        if (passed) {
            ctx.fireChannelRead(msg);
        } else {
            ReferenceCountUtil.release(msg); // 鉴权失败，释放消息
            log.warn("WebSocket 鉴权失败");
        }
    }

    // 获取 Token（从 URL 参数获取）
    private String getTokenFromRequest(HttpRequest req) {
        QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
        Map<String, List<String>> params = decoder.parameters();
        return params.containsKey("token") ? params.get("token").getFirst() : null;
    }

    private void sendHttpResponse(ChannelHandlerContext ctx) {
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.UNAUTHORIZED,
                Unpooled.wrappedBuffer("Unauthorized".getBytes())
        );
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}
